#pragma once

#include <iostream>
#include <string>
#include <vector>
#include <memory>
#include <unordered_map>
#include <sstream>
#include <fstream>
#include <functional>
#include <strings.h>
#include <string.h>
#include <vector>
#include "Log.hpp"
#include "Session.hpp"

static const std::string sep = "\r\n";
static const std::string header_sep = ": ";
static const std::string wwwroot = "wwwroot";
static const std::string homepage = "index.html";
static const std::string httpversion = "HTTP/1.0";
static const std::string space = " ";
static const std::string filesuffixsep = ".";
static const std::string args_sep = "?";

class HttpRequest;
class HttpResponse;

using func_t = std::function<std::shared_ptr<HttpResponse>(std::shared_ptr<HttpRequest>)>;

// http 内容，要根据目标要访问的 资源的文件后缀，区分清楚文件的类型，同时Content-Typed告诉浏览器，我们的response的正文的类型
//  构建http request请求
class HttpRequest
{
private:
    // 提取一行信息
    std::string GetOneLine(std::string &reqstr)
    {
        if (reqstr.empty())
            return reqstr;
        auto pos = reqstr.find(sep);
        if (pos == std::string::npos)
            return std::string();

        // 得到以\r\n分割的一行字符串
        std::string line = reqstr.substr(0, pos);
        // 将截取到的字符串去除
        reqstr.erase(0, pos + sep.size());
        // 这里做特殊处理，如果遇到了空行
        return line.empty() ? sep : line;
    }

    bool PaserHeaderHelper(const std::string &line, std::string *k, std::string *v)
    {
        auto pos = line.find(header_sep);
        if (pos == std::string::npos)
            return false;
        *k = line.substr(0, pos);
        *v = line.substr(pos + header_sep.size());
        return true;
    }

public:
    HttpRequest() : _blank_line(sep), _path(wwwroot)
    {
    }
    // 序列化
    void Serialize()
    {
    }
    // 反序列化
    void Derialize(std::string &reqstr)
    {
        _req_line = GetOneLine(reqstr);
        while (true)
        {
            std::string line = GetOneLine(reqstr);
            if (line.empty())
                break;
            else if (line == sep) // 读到空行，后面的全是正文
            {
                _req_text = reqstr;
                break;
            }
            else
            {
                _req_header.emplace_back(line);
            }
        }
        ParseReqLine();
        ParesHeader();
    }

    // 打印测试接口
    void Print()
    {
        std::cout << "===" << _req_line << std::endl;
        for (auto &header : _req_header)
        {
            std::cout << "***" << header << std::endl;
        }
        std::cout << _blank_line << std::endl;
        std::cout << _req_text << std::endl;

        std::cout << "-----------------------------------------------------------" << std::endl;
        std::cout << "method ###" << _method << std::endl;
        std::cout << "url ###" << _url << std::endl;
        std::cout << "path ###" << _path << std::endl;
        std::cout << "version ###" << _version << std::endl;
        for (auto &header : _headers)
        {
            std::cout << "@@@ " << header.first << " - " << header.second << std::endl;
        }
    }
    bool ParseReqLine()
    {
        if (_req_line.empty())
            return false;
        // 按照空格进行分离,解析Url
        std::stringstream ss(_req_line);
        ss >> _method >> _url >> _version;
        _path += _url;

        // 查找Cookie
        std::string perfix = "Cookie: "; // 写入： Set-Cookie: sessionid=1234 提交: Cookie: sessionid=1234
        for (auto &line : _req_header)
        {
            std::string cookie;
            if (strncmp(perfix.c_str(), line.c_str(), perfix.size()) == 0)
            {
                cookie = line.substr(perfix.size());
                LOG(INFO, "Cookie: %s\n", cookie.c_str());
                _cookie.emplace_back(cookie); // 截取"Cookie: "之后的就行了
            }
        }

        // 查找session
        perfix = "sessionid=";
        for (const auto &cookie : _cookie)
        {
            if (strncmp(perfix.c_str(), cookie.c_str(), perfix.size()) == 0)
            {
                _SessionId = cookie.substr(perfix.size());
                LOG(INFO, "Sessionid=%s\n", _SessionId.c_str());
            }
        }

        //LOG(INFO, "client want get %s, sessionid: %s, sessionid.empty(): %d\n", _path.c_str(), _SessionId.c_str(), _SessionId.empty());
        return true;
    }
    bool ParesHeader()
    {
        for (auto &header : _req_header)
        {
            std::string k, v;
            if (!PaserHeaderHelper(header, &k, &v))
                continue;
            _headers.insert(std::make_pair(k, v));
        }
        return true;
    }
    std::string Path()
    {
        return _path;
    }
    std::string Url()
    {
        return _url;
    }
    std::string SessionId()
    {
        return _SessionId;
    }
    ~HttpRequest()
    {
    }

private:
    // 原始协议
    std::string _req_line;                // 请求行
    std::vector<std::string> _req_header; // 请求报头
    std::string _blank_line;              // 空行
    std::string _req_text;                // 请求正文

    // 期望协议，将其key/vlue形式化
    // 这三个从请求行来
    std::string _method;
    std::string _url;
    std::string _args; // get方法中的参数
    std::string _path; // 访问资源的路径，虽然有了url但是他是非标准化的，所以这里还要单独的将url转化为path
    std::string _version;
    std::string _SessionId;
    // 这行从请求报文来
    std::unordered_map<std::string, std::string> _headers;
    std::vector<std::string> _cookie;
};

class HttpResponse
{
public:
    HttpResponse() : _version(httpversion), _blank_line(sep)
    {
    }
    ~HttpResponse()
    {
    }
    // 添加状态行
    void AddStatusLine(int code, const std::string &desc)
    {
        _code = code;
        _desc = desc; // 后面做优化
    }
    void AddHeander(const std::string &k, const std::string &v)
    {
        //LOG(INFO, "AddHeander: %s->%s\n", k.c_str(), v.c_str());
        _headers[k] = v;
    }
    void AddText(const std::string text)
    {
        _resp_text = text;
    }
    std::string Serialize()
    {
        // 状态行
        _status_line = _version + space + std::to_string(_code) + space + _desc + sep;
        // 响应报文
        for (auto &header : _headers)
        {
            _resp_header.emplace_back(header.first + header_sep + header.second + sep);
        }

        // 序列化
        std::string response = _status_line;
        for (auto &header : _resp_header)
        {
            response += header;
        }
        // 添加空行
        response += sep;
        // 添加正文
        response += _resp_text;
        return response;
    }

private:
    // 构建应答的必要字段
    std::string _version;                                  // 版本
    int _code;                                             // 状态码
    std::string _desc;                                     // 状态描述
    std::unordered_map<std::string, std::string> _headers; // 响应报头

    // 应答的结构化字段
    std::string _status_line;              // 请求行
    std::vector<std::string> _resp_header; // 响应报头
    std::string _blank_line;               // 空行
    std::string _resp_text;                // 响应正文
};

class Factory
{
public:
    static std::shared_ptr<HttpRequest> BuildHttpRequest()
    {
        return std::make_shared<HttpRequest>();
    }

    static std::shared_ptr<HttpResponse> BuildHttpResponse()
    {
        return std::make_shared<HttpResponse>();
    }
};

// 构建http response响应
class HttpServer
{
public:
    HttpServer()
    {
        _session_manager = std::make_unique<SessionManager>();
    }
    std::string ProveSession(const std::string &session_id)
    {
        return "sessionid=" + session_id + ";";
    }

    std::string HandlerHttpServer(std::string req)
    {
        std::cout << "------------------------" << std::endl;
        //std::cout << req << std::endl;

        auto request = Factory::BuildHttpRequest();
        auto response = Factory::BuildHttpResponse();
        request->Derialize(req);
        
        static int number = 0;
        if (request->Url() == "/login") // 用/login path向指定浏览器写入sessionid，并在服务器维护对应的session对象
        {
            std::string sessionid = request->SessionId();
            if (sessionid.empty()) // 说明历史没有登陆过
            {
                std::string user = "user-" + std::to_string(number++);
                session_ptr s = std::make_shared<Session>(user, "logined");
                std::string ssid = _session_manager->AddSession(s);
                LOG(DEBUG, "%s 被添加了, sessionid是: %s\n", user.c_str(), ssid.c_str());
                response->AddHeander("Set-Cookie", ProveSession(ssid));
            }
        }
        else
        {
            // 当浏览器在本站点任何路径中活跃，都会自动提交sessionid, 我们就能知道谁活跃了.
            std::string sessionid = request->SessionId();
            if (!sessionid.empty())
            {
                session_ptr s = _session_manager->GetSession(sessionid);
                // 这个地方有坑，一定要判断服务器端session对象是否存在，因为可能测试的时候
                // 浏览器还有历史sessionid，但是服务器重启之后，session对象没有了.
                if (s != nullptr)
                    LOG(DEBUG, "%s 正在活跃.\n", s->_username.c_str());
                else
                    LOG(DEBUG, "cookie : %s 已经过期, 需要清理\n", sessionid.c_str());
            }
        }
        response->AddStatusLine(200, "Ok");
        response->AddHeander("Content-Type: ", "text/html");
        response->AddText("<html><body><h1>hello world<h1><body><html>");
        return response->Serialize();
    }

private:
    std::unique_ptr<SessionManager> _session_manager;
};